/* Soubor je ulozen v kodovani UTF-8.
 * Kontrola kódování: Příliš žluťoučký kůň úpěl ďábelské ódy.
 */
package cz.pecinovsky.english.pojj.adv_demo.byt_lednička.hra;

import cz.pecinovsky.english.pojj.adv_framework.game_gui.IPlaceG;

import java.awt.Point;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static cz.pecinovsky.english.pojj.adv_demo.byt_lednička.hra.Předmět.TĚŽKÝ;
import static cz.pecinovsky.english.pojj.adv_demo.byt_lednička.hra.Texty.*;


/*******************************************************************************
 * Instance třídy {@code Místnost} představují jednotlive mistnosti
 * v prochazenem byte. Trida {@code Místnost} je soucasne schopna vybudovat
 * na zákadě zadných parametrů cely byt z jednotlivych mistnosti.
 *
 * @author    Rudolf PECINOVSKY
 * @version   5.0
 */
public enum Místnost implements IPlaceG
{
//== HODNOTY VÝČTOVÉHO TYPU ====================================================

    /** Vstupní mistnost bytu odkud  se dá přesunout do většiny místností. */
    Předsíň (new Point(550, 300),
        "Vstupní místnost bytu odkud  se dá přesunout do většiny místností.",
        new String[] { LOŽNICE, OBÝVÁK, KOUPELNA },
        TĚŽKÝ+BOTNÍK, DEŠTNÍK
//        new String[] { "Ložnice", "Obývák", "Koupelna" },
//        TĚŽKÝ+"Botník", "Deštník"
    ),

    /** Koupelna spojená se záchodem. */
    Koupelna (new Point(570, 100),
        "Koupelna spojená se záchodem.",
        new String[] { PŘEDSÍŇ },
        BRÝLE, TĚŽKÝ+UMYVADLO, ČASOPIS
//        new String[] { "Předsíň" },
//        "Brýle", TĚŽKÝ+"Umyvadlo", "Časopis"
    ),

    /** Druhá nejmilejší mistnost v bytě, v níž osazenstvo tráví
     *  mnohé příjemné chvilky. */
    Ložnice (new Point(460, 100),
        "Druhá nejmilejší místnost v bytě, v níž osazenstvo tráví " +
        "mnohé příjemné chvilky.",
        new String[] { KUCHYŇ, PŘEDSÍŇ },
        TĚŽKÝ+POSTEL, TĚŽKÝ+ZRCADLO, ŽUPAN
//        new String[] { "Kuchyň", "Předsíň" },
//        TĚŽKÝ+"Postel", TĚŽKÝ+"Zrcadlo", "Župan"
    ),

    /** Místnost, ve které se moc nezdržuju. */
    Obývák (new Point(200, 300),
        "Místnost, ve které se moc nezdržuju.",
        new String[] { KUCHYŇ, PŘEDSÍŇ },
        TĚŽKÝ+TELEVIZE
//        new String[] { "Kuchyň", "Předsíň" },
//        TĚŽKÝ+"Televize"
    ),

    /** Moje nejoblíbenější mistnost. */
    Kuchyň (new Point(200, 100),
        "Moje nejoblíbenější místnost.",
        new String[] { LOŽNICE, OBÝVÁK },
        TĚŽKÝ+LEDNIČKA, PAPÍR
//        new String[] { "Ložnice", "Obývák" },
//        TĚŽKÝ+"Lednička", "Papír"
    ),

    /** Nejčastější cíl mých výletů. */
    Lednička (new Point(30, 30),
        "Nejčastější cíl mých výletů.",
        new String[] {},
        "@"+PIVO, "@"+PIVO, "@"+PIVO, SALÁM, HOUSKA, "@"+VÍNO, "@"+RUM
//       new String[] {},
//        "@Pivo", "@Pivo", "@Pivo", "Salám", "Houska", "@Víno", "@Rum"
    );



//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================

    /** Mapa sloužící k převodu názvu místnosti na odpovídající místnost. */
    private static final Map<String,Místnost> název2místnost =
                                              new HashMap<String,Místnost>();



//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================

    private static Místnost aktuálníMístnost;



//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================

    //Teprve nyní existují všechny instance i všechny potřebné kontejnery,
    //a proto lze teprve nyní inicializovat sousedy místnosti
    static {
        //Zapamatuji si jména všech místností malými písmeny
        for (Místnost m : values()) {
            název2místnost.put(m.name().toLowerCase(), m);
        }
        //Jména výchozích sousedů převedu na sousedy a ty uložím
        for (Místnost m : values()) {
            for (int i=0;   i < m.názvyVýchozíchSousedů.length;   i++) {
                m.výchozíSousedé[i] = název2místnost.get(
                                      m.názvyVýchozíchSousedů[i].toLowerCase());
            }
            m.názvyVýchozíchSousedů = null;  //Už nebudou potřeba
        }
        inicializuj();
    }



//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================

    /** Popis významu a účelu dané místnosti. */
    private final String popis;

    /** Sousedé místnosti na začátku hry. */
    private final Místnost[] výchozíSousedé;

    /* Předměty v místnosti na počátku hry. */
    private final Předmět[] výchozíPředměty;

    /** Aktuální sousedé dané místnosti. */
    private final Collection<Místnost> sousedé  = new ArrayList<Místnost>();

    /** Předměty nacházející se aktuálně v místnosti. */
    private final Collection<Předmět>  předměty = new ArrayList<Předmět>();

    /** Pozice místnosti na plánku hry. */
    private final Point pozice;



//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================

    /** Pomocná proměnná používaná v konstruktoru třídy
     *  pro inicializaci pole výchozíSousedé. */
    private String[] názvyVýchozíchSousedů;



//== PŘÍSTUPOVÉ METODY ATRIBUTŮ TŘÍDY ==========================================

    /***************************************************************************
     * Vrátí odkaz na aktuálni místnost,
     * tj. na místnost, v níž se právě nachází hráč.
     *
     * @return Požadovaný odkaz
     */
    static Místnost getAktuálníMístnost()
    {
        return aktuálníMístnost;
    }


    /***************************************************************************
     * Nastaví zadanou místnost jako aktuální.
     *
     * @param místnost Nastavovaná aktuální místnost
     */
    static void setAktuálníMístnost(Místnost místnost) {
        aktuálníMístnost = místnost;
    }


    /***************************************************************************
     * Vrátí odkaz na místnost se zadaným názvem.
     *
     * @param název Název hledané místnosti
     * @return Požadovaný odkaz
     */
    static Místnost getMístnost(String název)
    {
        Místnost cil = název2místnost.get(název.toLowerCase());
        return cil;
    }


    /***************************************************************************
     * Vrátí kolekci odkazů na jednotlivé místnosti.
     *
     * @return Požadovaná kolekce
     */
    static Collection<Místnost> getMístnosti()
    {
        return new ArrayList<Místnost>(Arrays.asList(values()));
    }



//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

    /***************************************************************************
     * Inicializuje místnosti do výchozího stavu pro spuštění hry,
     * tj. nastavuje jim výchozí sousedy a výchozí přítomné předměty.
     * Metoda přitom předpokládá, že jsou již přihlášeni všichni posluchači.
     */
    static void inicializuj()
    {
        for (Místnost m : values()) {
            m.sousedé.clear();
            m.sousedé.addAll(Arrays.asList(m.výchozíSousedé));
            m.předměty.clear();
            m.předměty.addAll(Arrays.asList(m.výchozíPředměty));
        }
        aktuálníMístnost = Předsíň;
    }



//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     * Vytvoří mistnost se zadanými charakteristikami, popisem účelu místnosti,
     * pozicí případného návštěvníka (= pozicí na plánku),
     * seznamem možných sousedů (kam všude se dá z místnosti jít) a
     * seznamem v místnosti se vyskytujících předmětů.
     *
     * @param pozice   Pozice hráče na plánku bytu při pobytu v dané místnosti
     * @param popis    Popis účelu dané místnosti
     * @param sousedé  Pole s názvy sousedů dané místnosti, tj. s názvy
     *                 místností, do nichž se dá z dané místnosti přejít.
     * @param předměty Názvy předmětů, které se v místnosti vyskytují.
     *                 Konstruktor nechá tyto předměty vyrobit.
     */
    private Místnost(Point pozice, String popis,
                     String[] sousedé, String... předměty)
    {
        this.pozice = pozice;
        this.popis  = popis;
        this.názvyVýchozíchSousedů = sousedé;
        this.výchozíSousedé  = new Místnost[sousedé.length];
        this.výchozíPředměty = new Předmět [předměty.length];
        for (int i=0;   i < předměty.length;   i++ ) {
            Předmět předmět = new Předmět(předměty[i]);
            výchozíPředměty[i] = předmět;
        }
    }



//== ABSTRAKTNÍ METODY =========================================================
//== PŘÍSTUPOVÉ METODY INSTANCÍ ================================================

    /***************************************************************************
     * Vrati název mistnosti.
     *
     * @return Nazev mistnosti
     */
    @Override
    public String getName()
    {
        return name();
    }


    /***************************************************************************
     * Vrati popis mistnosti, ktery danou mistnost strucne charakterizuje.
     *
     * @return Pozadovany popis
     */
    @Override
    public String getDescription()
    {
        return popis;
    }


    /***************************************************************************
     * Vrati kolekci predmetu nachazejicich se v dane mistnosti.
     *
     * @return Pozadovana kolekce
     */
    @Override
    public Collection<Předmět> getObjects()
    {
        return Collections.unmodifiableCollection(předměty);
    }


    /***************************************************************************
     * Vrati kolekci mistnosti, do nichz je mozno se z teto mistnosti presunout.
     *
     * @return Pozadovana kolekce
     */
    @Override
    public Collection<Místnost> getNeighbors()
    {
        return Collections.unmodifiableCollection(sousedé);
    }


    /***************************************************************************
     * Vrátí pozici místnosti na plánu hry,
     * presněji pozici hráče nacházejícícho se v dané místnosti.
     * Na této pozici bude hráč při pobytu v dané místnosti zobrazen.
     *
     * @return Požadovaná pozice
     */
    @Override
    public Point getPosition()
    {
        return pozice;
    }



//== OSTATNÍ NESOUKROMÉ  METODY INSTANCÍ =======================================

    /***************************************************************************
     * Vrátí název dané instance.
     *
     * @return Nazev instance
     */
    @Override
    public String toString()
    {
        return name();
    }


    /***************************************************************************
     * Odlozi zadany predmet v mistnosti.
     *
     * @param  předmět odkladany v mistnosti
     */
    void polož( Předmět předmět ) {
        předměty.add( předmět );
    }


    /***************************************************************************
     * Odebere predmet zadaneho nazvu z mistnosti.
     * Odebrat je mozne pouze zvednutelné předměty.
     *
     * @param název Nazev odebiraneho predmetu
     * @return Byl-li předmět z místnosti odebrán, vrátí tento předmět.
     *         Nebyl-li předmět zvednutelný, vrátí předmět {@link TÍHA}.
     *         Nebyl-li v místnosti požadovaný předmět, vrátí {@code null}.
     */
    Předmět zvedni(String název)
    {
        String jméno;
        Předmět našel = null;
        for( Předmět předmět : předměty ) {
            jméno = předmět.getName();
            if (jméno.equalsIgnoreCase( název ))  {
                if (předmět.isTransportable())  {
                    předměty.remove(předmět);
                    našel = předmět;
                } else {
                    našel = Předmět.TÍHA;
                }
                break;
            }
        }
        return našel;
    }



//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
//== VNOŘENÉ A VNITŘNÍ TŘÍDY ===================================================
//== TESTOVACÍ METODY A TŘÍDY ==================================================
//
//     /***************************************************************************
//      * Testovací metoda.
//      */
//     public static void test()
//     {
//     }
//     /** @param args Parametry příkazového řádku - nepoužité. */
//     public static void main( String... args ) { test(); }
}
